home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mush-7.1.1 / msgs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-02  |  26.8 KB  |  975 lines

  1. /* @(#)msgs.c    (c) copyright 10/18/86 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4.  
  5. void
  6. display_msg(n, flg)
  7. register int n;
  8. u_long flg;
  9. {
  10.     char buf[32], *pager = NULL;
  11.  
  12.     if (ison(msg[n].m_flags, DELETE) && !do_set(set_options, "show_deleted")) {
  13.     print("Message %d deleted; ", n+1);
  14. #ifdef SUNTOOL
  15.     if (istool)
  16.         wprint("Select UNDELETE to read.\n");
  17.     else
  18. #endif /* SUNTOOL */
  19.     if (iscurses)
  20.         print_more("Type 'u' to undelete.");
  21.     else
  22.         wprint("Type 'undelete %d' to undelete\n", n+1);
  23.     return;
  24.     }
  25.     set_isread(n);
  26.     if (ison(flg, M_TOP)) {
  27.     turnon(flg, NO_HEADER);
  28.     print("Top of "), turnon(glob_flags, CONT_PRNT);
  29.     }
  30.  
  31. #ifdef MSG_SEPARATOR
  32.     turnon(flg, NO_SEPARATOR);
  33. #endif /* MMDF */
  34.     if (!istool && isoff(flg, NO_PAGE) &&
  35.         crt < msg[n].m_lines && isoff(flg, M_TOP)) {
  36.     if (!(pager = do_set(set_options, "pager")))
  37.         pager = DEF_PAGER;
  38.     if (!*pager || !strcmp(pager, "internal"))
  39.         pager = NULL; /* default to internal pager if pager set to "" */
  40.     }
  41.     (void) do_pager(pager, TRUE); /* start pager */
  42.     (void) do_pager(sprintf(buf, "Message #%d (%d lines)\n",
  43.              n+1, msg[n].m_lines), FALSE);
  44.     (void) copy_msg(n, NULL_FILE, flg, NULL);
  45.     (void) do_pager(NULL, FALSE); /* end pager */
  46. }
  47.  
  48. /*
  49.  * copy message 'n' to file "fp" according to various flag arguments
  50.  * return number of lines copied or -1 if system error on fputs.
  51.  * If "fp" is null, send to internal pager.  This can only happen from
  52.  * display_msg above.
  53.  */
  54. copy_msg(n, fp, flags, pattern)
  55. register int n;
  56. register FILE *fp;
  57. u_long flags;
  58. char *pattern;
  59. {
  60.     register int  ignoring = 0, lines = 0;
  61.     register char *indent_str, *p, *end_pat = NULL;
  62.     int          on_hdr = 1, top, squeeze = 0;
  63.     long      still_more = 0;
  64.     int          pat_len, pat_seek;
  65.     char       line[BUFSIZ], *show_hdrs = NULL;
  66.  
  67.     if (ison(flags, M_TOP)) {
  68.     p = do_set(set_options, "toplines");
  69.     top = (p)? atoi(p) : crt;
  70.     }
  71.     /* When updating to a folder, always write all headers! */
  72.     if (ison(flags, UPDATE_STATUS))
  73.     turnon(flags, NO_IGNORE);
  74.     else if (ison(flags, NO_IGNORE) &&
  75.         (p = do_set(set_options, "alwaysignore")) && !*p)
  76.     turnoff(flags, NO_IGNORE);    /* preserve historic behavior */
  77.     if (isoff(flags, NO_IGNORE)) {
  78.     if (do_set(set_options, "squeeze"))
  79.         squeeze = 1;
  80.     show_hdrs = do_set(set_options, "show_hdrs");
  81.     }
  82.     if (pattern && *pattern == '/' && (end_pat = index(pattern+1, '/'))) {
  83.     if (end_pat[1] == ',') {
  84.         pattern++;
  85.         *end_pat++ = 0;
  86.     } else
  87.         end_pat = NULL;
  88.     }
  89.     pat_len = pattern? strlen(pattern) : 0;
  90.     pat_seek = !!pat_len;
  91.  
  92. #ifdef SUNTOOL
  93.     xfree(more_prompt), more_prompt = NULL;
  94. #endif /* SUNTOOL */
  95.  
  96.     if (ison(flags, INDENT)) {
  97.     if ((indent_str = do_set(set_options, "pre_indent_str"))) {
  98.         fputs(format_hdr(n, indent_str, FALSE) + 9, fp); /* magic 9 !! */
  99.         fputc('\n', fp);
  100.     }
  101.     if (!(indent_str = do_set(set_options, "indent_str")))
  102.         indent_str = DEF_INDENT_STR;
  103.     }
  104.     /* "line" used as dummy here, since 0 bytes read */
  105.     if (!msg_get(n, line, 0)) {
  106.     error("Unable to find msg %d", n+1);
  107.     return -1;
  108.     }
  109.     while (still_more < msg[n].m_size && fgets(line, sizeof (line), tmpf)) {
  110.     still_more += strlen(line);
  111. #ifdef MSG_SEPARATOR
  112.     if (ison(flags, NO_SEPARATOR)) {
  113. #ifdef MMDF
  114.         if (!strncmp(line, MSG_SEPARATOR, 4))
  115. #else /* !MMDF */
  116.         if (!strncmp(line, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
  117. #endif /* MMDF */
  118.         continue;
  119.     }
  120. #endif /* MMDF */
  121.     /*
  122.      * If squeeze is one, all blanks lines squeeze down to one blank line.
  123.      * If squeeze is two, squeezing is in progress so wait for the next \n.
  124.      */
  125.     if (*line == '\n') {
  126.         if (on_hdr) {  /* blank line -- end of header */
  127.         on_hdr = 0;
  128.         if (ison(flags, NO_HEADER))
  129.             continue;
  130.         }
  131.         if (squeeze > 1 || pat_len && pat_seek)
  132.         continue;
  133.         else if (squeeze)
  134.         squeeze = 2;
  135.     } else {
  136.         if (squeeze > 1)
  137.         squeeze = 1;
  138.         if (pat_len && (!on_hdr || isoff(flags, NO_HEADER))) {
  139.         /* If we're looking for a pattern for mush-pipe, then
  140.          * continue if this line doesn't match the pattern.
  141.          */
  142.         if (pat_len == 0)
  143.             continue;
  144.         Debug("Seeking (%s) in (%s)", pattern, line);
  145.         if (strncmp(line, pattern, pat_len)) {
  146.             if (pat_seek)
  147.             continue;
  148.         } else if (end_pat && *end_pat++ == ',') {
  149.             pattern = end_pat;
  150.             if (*pattern == '/') {
  151.             pattern++;
  152.             if (end_pat = index(pattern, '/'))
  153.                 *end_pat++ = 0;
  154.             }
  155.             pat_len = pattern? strlen(pattern) : 0;
  156.             pat_seek = !pat_seek;
  157.         } else {
  158.             pat_len = 0;
  159.             pat_seek = !pat_seek;
  160.         }
  161.         }
  162.     }
  163.  
  164.     if (ison(flags, UPDATE_STATUS))
  165.         if (!strncmp(line, "Status:", 7))
  166.         continue; /* ignore this and other "Status" lines */
  167.         else if (!on_hdr) {
  168.         /* preserve NEW/UNREAD status on preserved messages */
  169.         p = line;
  170.         p += Strcpy(p, "Status: O");
  171.         if (isoff(msg[n].m_flags, UNREAD) &&
  172.             isoff(msg[n].m_flags, PRESERVE))
  173.             *p++ = 'R';
  174.         if (ison(msg[n].m_flags, SAVED))
  175.             *p++ = 'S';
  176.         if (ison(msg[n].m_flags, REPLIED))
  177.             *p++ = 'r';
  178.         if (ison(msg[n].m_flags, PRINTED))
  179.             *p++ = 'p';
  180.         if (ison(msg[n].m_flags, FORWARD))
  181.             *p++ = 'f';
  182.         *p++ = '\n', *p = 0;
  183.         (void) fputs(line, fp);
  184.         line[0] = '\n', line[1] = '\0';
  185.         turnoff(flags, UPDATE_STATUS);
  186.         }
  187.     if (on_hdr && (isoff(flags, NO_IGNORE) || ison(flags, FORWARD))) {
  188.         p = any(line, " \t:");
  189.         if (!p)
  190.         ignoring = 0, on_hdr = 0;
  191.         else if (ignoring)
  192.         if (*p != ':') {
  193.             Debug("Ignoring: %s", line);
  194.             continue;
  195.         } else
  196.             ignoring = 0;
  197.         if (p && *p == ':') {
  198.         *p = 0;
  199.         ignoring = 0;
  200.         if (ison(flags, FORWARD)) {
  201.             if (chk_two_lists(line, IGNORE_ON_FWD, ":, \t"))
  202.             ignoring = 1;
  203.         } else if (show_hdrs) {
  204.             if (!chk_two_lists(line, show_hdrs, ":, \t"))
  205.             ignoring = 1;
  206.         } else {
  207.             register struct options *opts;
  208.             for (opts = ignore_hdr; opts; opts = opts->next)
  209.             if (!lcase_strncmp(opts->option, line, -1)) {
  210.                 ignoring = 1;
  211.                 break;
  212.             }
  213.         }
  214.         *p = ':';
  215.         if (ignoring) {
  216.             Debug("Ignoring: %s", line);
  217.             continue;
  218.         }
  219.         }
  220.     }
  221.     if (!on_hdr && ison(flags, M_TOP) && !--top)
  222.         break;
  223.     if (!on_hdr && (still_more < msg[n].m_size || line[0] != '\n') ||
  224.         isoff(flags, NO_HEADER)) {
  225.         /* note that function returns the number of lines */
  226.         lines++;
  227.         if (ison(flags, INDENT))
  228.         (void) fputs(indent_str, fp);
  229.         if (!fp) {
  230.         if (do_pager(line, FALSE) == EOF)
  231.             return -1;
  232.         } else if (fputs(line, fp) == EOF)
  233.         /* Pipe broken, out of file space, etc */
  234.         return -1;
  235.     }
  236.     if (pat_seek && !pat_len)
  237.         break; /* Skip the rest */
  238.     }
  239.     if (ison(flags, INDENT) &&
  240.     (indent_str = do_set(set_options, "post_indent_str")) && *indent_str) {
  241.     (void) fprintf(fp, "%s\n", format_hdr(n, indent_str, FALSE)+9);
  242.     }
  243.     if (fp && fflush(fp) == EOF)
  244.     return -1;    /* Write failure? */
  245.     return lines;
  246. }
  247.  
  248. /*
  249.  * copy tempfile back to folder.
  250.  * Return 1 on success, 0 on failure.
  251.  */
  252. copyback(prompt)
  253. char *prompt;
  254. {
  255.     register int    i = 0, held = 0, saved = 0;
  256.     register u_long    flg = 0;
  257.     register FILE    *mbox = NULL_FILE, *mail_fp = NULL_FILE;
  258. #ifdef SYSV
  259.     FILE         *save_mail_fp = NULL_FILE;
  260. #endif /* SYSV */
  261.     char        *mbox_file, action = 0;
  262.     int         hold = 0, delete_it = 0, dont_unlink = FALSE;
  263.     int            isspool, keepsave, write_err = FALSE;
  264.     static int        first = 1;
  265.  
  266.     /*
  267.      * if there is new mail in this folder, the user is notified and
  268.      * prompted if he really wants to update the folder.  He's either
  269.      * quitting or changing folders, so let him read the new mail first.
  270.      */
  271.     if (!first && mail_size()) {
  272. lost_lock:
  273.     if (get_new_mail(TRUE) && prompt && isoff(glob_flags, REDIRECT)
  274.         && show_new_mail()) {
  275.         char buf[80];
  276.         if (iscurses)
  277.         putchar('\n'), turnon(glob_flags, CNTD_CMD);
  278.         if (!istool)
  279.         print("%s [n] ", prompt);
  280.         buf[0] = 0;
  281. #ifdef SUNTOOL
  282.         if (istool) {
  283.         (void) sprintf(buf, "New mail -- %s", prompt);
  284.         if (ask(buf) != TRUE)
  285.             return 0;
  286.         } else
  287. #endif /* SUNTOOL */
  288.         if (!Getstr(buf, sizeof (buf), 0) || lower(*buf) != 'y')
  289.             return 0;
  290.     }
  291.     }
  292.     first = 0;
  293.  
  294.     /* If the user hasn't changed anything, just return true */
  295.     if (isoff(glob_flags, DO_UPDATE))
  296.     return 1;
  297.     if (ison(glob_flags, READ_ONLY)) {
  298.     print("Unable to update %s: read only\n", mailfile);
  299.     return 0; /* user should use "exit" instead of "quit". */
  300.     }
  301.     if (!msg_cnt) /* prevent unnecessary overwrite */
  302.     return 1;
  303.  
  304. #ifdef SUNTOOL
  305.     if (istool) {
  306.     (void) notify_set_itimer_func(tool, do_check,
  307.         ITIMER_REAL, (struct itimerval *) 0, (struct itimerval *) 0);
  308.     }
  309. #endif /* SUNTOOL */
  310.  
  311.     /* We can't lock a file unless we have an fd, but "w+" will zero
  312.      * the file.  If the lock later failed for any reason (possible
  313.      * race condition with an MTA), we would lose all current mail.
  314.      * So, open read/write (if possible) and truncate later.
  315.      */
  316.     if (!(mail_fp = lock_fopen(mailfile, "r+"))) {
  317.     error("WARNING: unable to lock %s -- update aborted", mailfile);
  318. #ifdef SUNTOOL
  319.     write_err = 1;    /* forces return 0; below */
  320.     goto resume_timer;    /* blecch */
  321. #else /* !SUNTOOL */
  322.     return 0;
  323. #endif /* SUNTOOL */
  324.     }
  325.     /* Make sure no mail arrived between the last check and when we
  326.      * got the lock.  If it did, release the lock and try again.
  327.      */
  328.     if (mail_size()) {
  329.     (void) close_lock(mailfile, mail_fp);
  330.     goto lost_lock;
  331.     }
  332.  
  333.     /* open mbox if: "autodelete" AND "hold" are NOT set. */
  334.     if (!strcmp(mailfile, spoolfile)
  335.         && !(delete_it = !!do_set(set_options, "autodelete"))
  336.         && !(hold = !!do_set(set_options, "hold"))) {
  337.     register char *p;
  338.     int x = 1; /* tell getpath to ignore "ENOENT" if file not found */
  339.  
  340.     if (!(p = do_set(set_options, "mbox")))
  341.         p = DEF_MBOX;
  342.     mbox_file = getpath(p, &x); /* static data -- copy? */
  343.     if (x) {
  344.         if (x > 0)
  345.         print("%s is a directory.\n", mbox_file);
  346.         else
  347.         print("Unable to open %s: %s\n", p, mbox_file);
  348.         mbox = NULL_FILE;
  349.     } else {
  350.         if (Access(mbox_file, F_OK) == -1) /* does it exist? */
  351.         mbox = lock_fopen(mbox_file, "w");
  352.         else
  353.         mbox = lock_fopen(mbox_file, "a");
  354.         if (!mbox)
  355.         error("Unable to write to %s", mbox_file);
  356.     }
  357.     }
  358.  
  359.     /* ignore signals before truncating */
  360.     turnon(glob_flags, IGN_SIGS);
  361. #ifdef SYSV
  362.     /* SysV can't truncate a file in the middle, so we can't just
  363.      * write to mail_fp and close.  Instead, we save the mail_fp
  364.      * and reopen for writing, ignoring our own lock.  After updating,
  365.      * we can safely fclose both file pointers.
  366.      */
  367.     save_mail_fp = mail_fp;
  368.     /* This could fail if we run out of file descriptors */
  369.     if (!(mail_fp = fopen(mailfile, "w"))) {
  370.     error("WARNING: unable to reopen %s for update", mailfile);
  371.     if (save_mail_fp)
  372.         (void) close_lock(mailfile, save_mail_fp);
  373.     if (mbox)
  374.         (void) close_lock(mbox_file, mbox);
  375.     turnoff(glob_flags, IGN_SIGS);
  376.     return 0;
  377.     }
  378. #endif /* SYSV */
  379.  
  380.     print("Updating \"%s\"", mailfile);
  381.  
  382.     turnon(flg, UPDATE_STATUS);
  383.  
  384.     keepsave = !!do_set(set_options, "keepsave");
  385.     isspool = !strcmp(mailfile, spoolfile);
  386.  
  387.     for (i = 0; i < msg_cnt; i++) {
  388.     /* Maintain the current message across update; if this turns out
  389.      * to be unnecessary (changing folders), folder() will reset it.
  390.      */
  391.     if (current_msg == i)
  392.         current_msg = held;
  393.     /* Check to see if message is marked for deletion or, if read and not
  394.      * preserved, delete it if autodelete is set.  Otherwise, if hold is
  395.      * set save the message in the spool file.  If all fails, save in mbox.
  396.      */
  397.     if (ison(msg[i].m_flags, DELETE)
  398.     ||  ison(msg[i].m_flags, SAVED) && !keepsave &&
  399.         isoff(msg[i].m_flags, PRESERVE) && isspool
  400.     ||  isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE) 
  401.         && delete_it) {
  402.         Debug("%s %d",
  403.         (action!='d')? "\ndeleting message:" : "", i+1), action = 'd';
  404.         continue;
  405.     } else if (ison(msg[i].m_flags, UNREAD) ||
  406.          ison(msg[i].m_flags, PRESERVE) || hold || !mbox) {
  407.         Debug("%s %d",
  408.         (action!='s')? "\nsaving in spool:" : "", i+1), action = 's';
  409.         if (copy_msg(i, mail_fp, flg, NULL) == -1) {
  410.         error("WARNING: unable to write back to spool");
  411.         print_more("ALL mail left in %s\n", tempfile);
  412.         print_more("Spool mailbox may be corrupted.\n");
  413.         dont_unlink = TRUE;
  414.         write_err = TRUE;
  415.         break;
  416.         }
  417.         held++;
  418.     } else if (isspool) {   /* copy back to mbox */
  419.         if (copy_msg(i, mbox, flg, NULL) == -1) {
  420.         error("WARNING: unable to write to mbox");
  421.         print_more("Unresolved mail left in %s\n", tempfile);
  422.         dont_unlink = TRUE;
  423.         write_err = TRUE;
  424.         break;
  425.         }
  426.         saved++;
  427.         Debug("%s %d",
  428.         (action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm';
  429.     }
  430.     }
  431.     if (write_err)
  432.     current_msg = 0;
  433.     else if (current_msg == held)
  434.     current_msg--;    /* Don't point to a message that got deleted */
  435.     Debug("\n%s", mailfile);
  436.  
  437. #ifdef SYSV
  438.     /* Close the write file pointer first */
  439.     (void) fclose(mail_fp);
  440.     mail_fp = save_mail_fp;
  441. #else /* !SYSV */
  442.     /* Truncate the file at the end of what we just wrote.
  443.      * If you aren't SYSV and you still can't ftruncate(),
  444.      * you're out of luck?
  445.      */
  446.     (void) ftruncate(fileno(mail_fp), ftell(mail_fp));
  447. #endif /* SYSV */
  448.  
  449.     /* some users like to have zero length folders for frequent usage */
  450.     if (mbox && close_lock(mbox_file, mbox) == EOF) {
  451.     error("WARNING: unable to close mbox");
  452.     print_more("Unresolved mail left in %s\n", tempfile);
  453.     dont_unlink = TRUE;
  454.     write_err = TRUE;
  455.     }
  456.     if (held) {
  457.     print_more(": saved %d message%s\n", held, (held==1)? NO_STRING: "s");
  458.     } else
  459. #ifdef HOMEMAIL
  460.     if (!dont_unlink && !do_set(set_options, "save_empty"))
  461. #else /* HOMEMAIL */
  462.     if (strcmp(mailfile, spoolfile) && !dont_unlink &&
  463.     !do_set(set_options, "save_empty"))
  464. #endif /* HOMEMAIL */
  465.     if (unlink(mailfile))
  466.         turnon(glob_flags, CONT_PRNT), error(": cannot remove");
  467.     else {
  468.         print_more(": removed\n");
  469.         held = -1;
  470.     }
  471.     else
  472.     print_more(": empty\n");
  473.     if (saved)
  474.     print("saved %d message%s in %s\n",
  475.                 saved,(saved==1)? NO_STRING:"s", mbox_file);
  476.  
  477.     if (held > 0) {
  478.     /* Reset the access time of the spool file to prevent
  479.      * bogus "new mail" messages from the shell.
  480.      */
  481.     long times[2];
  482.     (void) fflush(mail_fp); /* just in case */
  483.     times[1] = time(×[0]) - (long)2;
  484.     if (!strcmp(mailfile, spoolfile) && utime(mailfile, times))
  485.         error("utime");
  486.     }
  487.  
  488.     if (close_lock(mailfile, mail_fp) == EOF) {
  489.     error("WARNING: unable to close spool");
  490.     print_more("ALL mail left in %s\n", tempfile);
  491.     print_more("Spool mailbox may be corrupted.\n");
  492.     write_err = TRUE;
  493.     }
  494.  
  495. #ifdef SUNTOOL
  496.     if (istool) {
  497. resume_timer:
  498.     mail_timer.it_value.tv_sec = time_out;
  499.     mail_timer.it_interval.tv_sec = time_out;
  500.     (void) notify_set_itimer_func(tool, do_check,
  501.         ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
  502.     }
  503. #endif /* SUNTOOL */
  504.  
  505.     turnoff(glob_flags, IGN_SIGS);
  506.  
  507.     /* Return nonzero for success, -1 if file removed */
  508.     if (write_err)
  509.     return 0;
  510.     else if (held < 0)
  511.     return -1;
  512.     else
  513.     return 1;
  514. }
  515.  
  516. /*
  517.  * check the sizes of the current folder (file) and the spool file.
  518.  * spool_size is the size in bytes of the user's main mailbox.
  519.  * last_size is the size of the _current_ folder the last time we checked.
  520.  * return true if the current folder has new mail.  check_new_mail() checks
  521.  * for new mail in the system mailbox since it checks against last_spool_size.
  522.  */
  523. mail_size()
  524. {
  525.     struct stat buf;
  526.  
  527.     if (!stat(spoolfile, &buf))
  528.     spool_size = buf.st_size;
  529.     else if (!strcmp(mailfile, spoolfile))
  530.     return 0;
  531.     if (!is_shell || ison(glob_flags, IS_SENDING))
  532.     return 0;
  533.     if (strcmp(mailfile, spoolfile) && stat(mailfile, &buf)) {
  534.     if (errno != ENOENT)
  535.         error("Unable to stat %s", mailfile);
  536.     return 0;
  537.     }
  538.     if (buf.st_size != last_size) {
  539.     last_size = buf.st_size;
  540.     return 1;
  541.     }
  542.     return 0;
  543. }
  544.  
  545. static
  546. struct mailstat {
  547.     int new, unread, deleted;
  548. } mail_stat;
  549.  
  550. void
  551. mail_status(as_prompt)
  552. {
  553.     char buf[MAXPATHLEN];
  554.     register int cnt;
  555.  
  556.     mail_stat.new = mail_stat.unread = mail_stat.deleted = 0;
  557.  
  558.     for (cnt = 0; cnt < msg_cnt; cnt++) {
  559.     if (ison(msg[cnt].m_flags, UNREAD))
  560.         mail_stat.unread++;
  561.     if (ison(msg[cnt].m_flags, DELETE))
  562.         mail_stat.deleted++;
  563.     if (isoff(msg[cnt].m_flags, OLD))
  564.         mail_stat.new++;
  565.     }
  566.     if (as_prompt) {
  567.     /* use %s in case prompt has any %'s in it */
  568.     print("%s", format_prompt(current_msg, prompt));
  569.     return;
  570.     }
  571.     (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread",
  572.     trim_filename(mailfile),
  573.     ison(glob_flags, READ_ONLY)? " [read only]" : "",
  574.     msg_cnt, (msg_cnt != 1)? "s": NO_STRING,
  575.     mail_stat.new, mail_stat.unread);
  576.     if (istool || iscurses)
  577.     (void) sprintf(buf+strlen(buf), ", %d deleted", mail_stat.deleted);
  578. #ifdef SUNTOOL
  579.     if (istool) {
  580.     static char ic_text[4];
  581.     char *lbl;
  582.     Icon icon;
  583.     extern struct pixrect mail_icon_image1, mail_icon_image2;
  584.     (void) sprintf(ic_text, "%3d", msg_cnt);
  585.     if (!(lbl = (char *)window_get(tool, FRAME_LABEL)) || strcmp(lbl, buf))
  586.         (void) window_set(tool, FRAME_LABEL, buf, NULL);
  587.     icon = (Icon) window_get(tool, FRAME_ICON);
  588.     (void) icon_set(icon,
  589.         ICON_IMAGE, ison(glob_flags, NEW_MAIL)?
  590.                 &mail_icon_image2 : &mail_icon_image1,
  591.         NULL);
  592.     if (!chk_option("quiet", "iconlabel"))
  593.         (void) icon_set(icon, ICON_LABEL, ic_text, NULL);
  594.     else
  595.         (void) icon_set(icon, ICON_LABEL, NO_STRING, NULL);
  596.     (void) window_set(tool, FRAME_ICON, icon, NULL);
  597.     } else
  598. #endif /* SUNTOOL */
  599.  
  600. #ifdef CURSES
  601.     if (iscurses) {
  602.         move (0, 0);
  603.         printw("%-3d %-.*s",
  604.         ((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol();
  605.     } else
  606. #endif /* CURSES */
  607.         puts(buf);
  608.     return;
  609. }
  610.  
  611. /*
  612.  * Construct a prompt for the given message number using the given format
  613.  */
  614. char *
  615. format_prompt(num, fmt)
  616. int num;
  617. char *fmt;
  618. {
  619.     static char buf[MAXPATHLEN];
  620.     register char *p, *b = buf, *mf;
  621.  
  622.     if (is_shell)
  623.     mf = mailfile;
  624.     else
  625.     mf = "[no folder]";
  626.  
  627.     for (p = fmt; *p; p++)
  628.     if (*p == '\\')
  629.         switch (*++p) {
  630.         case 'n': case 'r': *b++ = '\n';
  631.         when 't': *b++ = '\t';
  632.         otherwise: *b++ = *p;
  633.         }
  634.     else if (*p == '%')
  635.         switch (*++p) {
  636.         case 'm':
  637.             b += strlen(sprintf(b,"%d",(msg_cnt)? num + 1 : 0));
  638.         when 't':
  639.             b += strlen(sprintf(b, "%d", msg_cnt));
  640.         when 'd':
  641.             b += strlen(sprintf(b, "%d", mail_stat.deleted));
  642.         when 'u':
  643.             b += strlen(sprintf(b, "%d", mail_stat.unread));
  644.         when 'n':
  645.             b += strlen(sprintf(b, "%d", mail_stat.new));
  646.         when 'f':
  647.         {
  648.             char *tail = rindex(mf, '/'); 
  649.             if (tail && tail[1])
  650.             b += Strcpy(b, tail+1);
  651.             else {
  652.             /* Fall through */
  653.         case 'F':
  654.             b += Strcpy(b, mf);
  655.             }
  656.             if (ison(glob_flags, READ_ONLY))
  657.             b += Strcpy(b, " [read-only]");
  658.         }
  659.         when 'T': case 'D': case 'Y': case 'y':
  660.         case 'M': case 'N': case 'W':
  661.             b += Strcpy(b, Time(p, (long)0));
  662.         otherwise: *b++ = *p;
  663.         }
  664.     else if (*p == '!')
  665.         b += strlen(sprintf(b, "%d", hist_no+1));
  666.     else
  667.         *b++ = *p;
  668.     *b = 0;
  669.     return buf;
  670. }
  671.  
  672. /*
  673.  *  For uucp mailers that use >From lines with "remote from <path>":
  674.  * (where "path" is a hostname or pathnames)
  675.  *
  676.  *  a. Set the return_path to the empty string.
  677.  *  b. For each From_ or >From_ line:
  678.  *  c. Save the username (second token).
  679.  *  d. Save the date (3-7 tokens).
  680.  *  e. If it has a "remote from" then append the remote host
  681.  *    (last token) followed by a "!" to the return_path.
  682.  *  f. If the saved username has a '@' but no '!' then convert it
  683.  *    to UUCP path form.
  684.  *  g. Append the saved username to return_path.
  685.  */
  686. parse_from(fp, path)
  687. FILE *fp;
  688. char path[];
  689. {
  690.     char user[256], buf[256]; /* max size for each line in a mail file */
  691.     register char *p;
  692.     long save_offset = ftell(fp);
  693.  
  694.     path[0] = '\0';
  695.     while (fgets(buf, sizeof buf, fp)) {
  696.     if (strncmp(buf, ">From ", 6))
  697.         break;
  698.     p = buf + 6;
  699.  
  700.     (void) sscanf(p, "%s", user);
  701.  
  702.     while (p = index(p+1, 'r')) {
  703.         if (!strncmp(p, "remote from ", 12)) {
  704.         char *p2 = path+strlen(path);
  705.         skipspaces(12);
  706.         (void) sscanf(p, "%s", p2); /* add the new machine to current path */
  707.         (void) strcat(p2, "!");
  708.         break;
  709.         }
  710.     }
  711.  
  712.     if (p)
  713.         (void) bang_form(path + strlen(path), user);
  714.     save_offset = ftell(fp);
  715.     }
  716.     (void) fseek(fp, save_offset, L_SET);
  717. }
  718.  
  719. /*
  720.  * Scan a file and select messages from it and append them to the current folder
  721.  *
  722.  * If "append" is 1, start where we left off (held in msg[cnt].m_offset)
  723.  * and scan for messages.  Append all messages found until EOF.
  724.  *
  725.  * If "append" is 2, we're merging in a new file, so start at the end of
  726.  * the present folder and append all messages found until EOF.
  727.  *
  728.  * If "append" is 0, then the message separator must exist once and
  729.  * only once.  All extra occurrences of the separator is preceded by a '>'.
  730.  * The list argument will be the message number to replace in the current
  731.  * folder with the message read in from other filename.
  732.  */
  733. load_folder(file, append, list)
  734. char *file, *list;
  735. int append;
  736. {
  737.     char    buf[BUFSIZ];
  738.     int        lines = 0, msg_found = 0, had_error = 1;
  739.     int        get_status = 1, cnt;
  740.     long    bytes, ftell();
  741.     struct msg  old;
  742.     char    *p, date[64];
  743.     FILE    *fp;
  744. #ifdef MMDF
  745.     int        begin_sep = 0; /* track beginning vs ending separators */
  746. #endif /* MMDF */
  747.  
  748.     if (!(fp = lock_fopen(file, "r"))) {
  749.     error("Unable to open %s", file);
  750.     return -1;
  751.     }
  752.  
  753.     if (append) {
  754.     cnt = msg_cnt;
  755.     (void) fseek(fp, append == 1 ? msg[cnt].m_offset : 0L, L_SET);
  756.     } else {
  757.     cnt = (int)list;
  758.     old = msg[cnt];
  759.     }
  760.  
  761.     if (isoff(glob_flags, READ_ONLY)) {
  762.     if (tmpf)
  763.         (void) fclose(tmpf);
  764.     if (!(tmpf = mask_fopen(tempfile, "a"))) {
  765.         error("Unable to open %s for appending", tempfile);
  766.         close_lock(file, fp);
  767.         return -1;
  768.     }
  769.     (void) fseek(tmpf, 0L, 2); /* assure we're at the end of the file */
  770.     } else if (append == 2) {
  771.     /* you can't merge in a folder to a read-only folder */
  772.     close_lock(file, fp);
  773.     return -1;
  774.     }
  775.  
  776. #ifdef MMDF
  777.     if (!append) {
  778.     (void) strcpy(buf, MSG_SEPARATOR);
  779.     goto do_headers;
  780.     }
  781. #endif /* MMDF */
  782.     buf[0] = 0;
  783.     while (fgets(buf, sizeof (buf), fp)) {
  784. #ifndef MSG_SEPARATOR
  785.     int warn = ison(glob_flags, WARNING);
  786.     turnoff(glob_flags, WARNING);
  787.     if (!strncmp(buf, "From ", 5)) {
  788.         p = buf + 5;    /* skip "From " */
  789.         skipspaces(0);
  790.         p = any(p, " \t");    /* skip the address */
  791.     } else
  792.         p = buf;
  793.     if (p > buf && (p = parse_date(p + 1)) && strcpy(date, p))
  794. #else /* MSG_SEPARATOR */
  795.     if (!strncmp(buf, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
  796. #endif /* MSG_SEPARATOR */
  797.     {
  798. #ifdef MMDF
  799.         if (!append)
  800.         (void) fputc('>', tmpf);
  801.         else if (begin_sep = !begin_sep)
  802. do_headers:
  803. #else /* MMDF */
  804.         if (!append && msg_found)
  805.         (void) fputc('>', tmpf);
  806.         else
  807. #endif /* MMDF */
  808.         {
  809.         msg_found++;
  810.         had_error = 0;
  811.         if (append && cnt == MAXMSGS-append) {
  812.             wprint("WARNING: exceeded %d messages.\n", MAXMSGS-append);
  813.             wprint("Not all messages have been loaded.\n");
  814.             msg_cnt--;
  815.             had_error++;
  816.             break;
  817.         }
  818.         if (ison(glob_flags, READ_ONLY))
  819.             bytes = ftell(fp) - strlen(buf);
  820.         else {
  821.             char path[256];
  822.             parse_from(fp, path);
  823.             if (path[0])
  824.             (void)sprintf(buf,"From %s %s", path,
  825.                         date_to_ctime(date));
  826.             bytes = ftell(tmpf);
  827.         }
  828.         /* finish up message structure from previous message.
  829.          * if this is incorporating new mail, check "lines" to
  830.          * see if previous message has already been set!
  831.          */
  832.         if (cnt && lines) {
  833.             msg[cnt-1].m_size = bytes - msg[cnt-1].m_offset;
  834.             msg[cnt-1].m_lines = lines;
  835.         }
  836.         if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  837.             error(tempfile);
  838.             had_error++;
  839.             break;
  840.         }
  841.         msg[cnt].m_offset = bytes;
  842.         msg[cnt].m_flags = 0L;
  843. #ifdef MSG_SEPARATOR
  844.         lines = 0;
  845. #else /* MSG_SEPARATOR */
  846.         lines = 1; /* count the From_ line */
  847.         if (warn)
  848.             turnon(glob_flags, WARNING);
  849.         strdup(msg[cnt].m_date_recv, date);
  850. #endif /* MSG_SEPARATOR */
  851.         turnon(msg[cnt].m_flags, UNREAD); /* initialize */
  852.         /* we've read the "From " line(s), now read the rest of
  853.          * the message headers till we get to a blank line.
  854.          */
  855.         while (fgets(buf, sizeof (buf), fp) && (*buf != '\n')) {
  856.             p = buf;
  857.             if (!strncmp(buf, "Date:", 5))
  858.             strdup(msg[cnt].m_date_sent, parse_date(p+5));
  859.             if (get_status &&
  860.                 !(get_status = strncmp(p, "Status:", 7))) {
  861.             /* new mail should not have a Status: field! */
  862.             turnon(msg[cnt].m_flags, OLD);
  863.             for (p += 7 ; *p != '\n'; p++) {
  864.                 if (isspace(*p))
  865.                 continue;
  866.                 switch(*p) {
  867.                 case 'R': turnoff(msg[cnt].m_flags, UNREAD);
  868.                 when 'P': turnon(msg[cnt].m_flags, UNREAD);
  869.                 when 'N': turnon(msg[cnt].m_flags, UNREAD);
  870.                       turnoff(msg[cnt].m_flags, OLD);
  871.                 when 'S': turnon(msg[cnt].m_flags, SAVED);
  872.                 when 'r': turnon(msg[cnt].m_flags, REPLIED);
  873.                 when 'O': ; /* do nothing */
  874.                 when 'f': turnon(msg[cnt].m_flags, FORWARD);
  875.                 when 'p': turnon(msg[cnt].m_flags, PRINTED);
  876.                 otherwise :
  877.                     if (ison(glob_flags, WARNING))
  878.                     print("unknown msg status flag: %c\n",
  879.                         *p);
  880.                 }
  881.             }
  882.             }
  883.             if (isoff(glob_flags,READ_ONLY) && fputs(buf, tmpf) == -1) {
  884.             error(tempfile);
  885.             had_error++;
  886.             break;
  887.             }
  888.             lines++;
  889.         }
  890.         if (!msg[cnt].m_date_sent || !*msg[cnt].m_date_sent)
  891.             if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv) {
  892.             wprint("Message %d has *no* date!?\n", cnt+1);
  893.             msg[cnt].m_date_sent = msg[cnt].m_date_recv =
  894.                 "0000000000XXX";
  895.             } else
  896.             strdup(msg[cnt].m_date_sent, msg[cnt].m_date_recv);
  897.         else if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv)
  898.             strdup(msg[cnt].m_date_recv, msg[cnt].m_date_sent);
  899.         if (had_error)
  900.             break;
  901.         if (append && list)
  902.             set_msg_bit(list, cnt);
  903.         if (append)
  904.             cnt = ++msg_cnt;
  905.         get_status = 1;
  906.         }
  907.     } else if (!msg_found && buf[0] != '\n') {
  908.         /* Allow leading blank lines, but anything else is wrong */
  909.         lines++;
  910.         had_error++;
  911.         break;
  912.     }
  913.     if (msg_found) {
  914.         lines++;
  915.         if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  916.         error(tempfile);
  917.         had_error++;
  918.         break;
  919.         }
  920.     }
  921.     }
  922.     if (msg_found && append != 1)
  923.     turnon(glob_flags, DO_UPDATE);
  924. #ifdef MMDF
  925.     if (!append)
  926.     (void) fputs(END_MSG_SEP, tmpf);
  927. #endif /* MMDF */
  928.     if (had_error) {
  929.     if (!append)
  930.         msg[cnt] = old;
  931.     else if (msg_found && append == 1 && cnt == MAXMSGS-append) {
  932.         /* reset fp to the beginning of the not-loaded message */
  933.         bytes = ftell(fp) - strlen(buf);
  934.         (void) fseek(fp, bytes, L_SET);
  935.     }
  936.     if (!msg_found) {
  937.         if (!append)
  938.         print("File not left in correct message format.\n");
  939.         else if (cnt == 0) {
  940.         if (buf[0]) 
  941.             print("\"%s\" does not seem to be a folder\n", file);
  942.         else
  943.             had_error = 0;    /* empty files are OK */
  944.         }
  945.     }
  946.     } else {
  947.     if (append)
  948.         cnt--;
  949.     if (isoff(glob_flags, READ_ONLY))
  950.         msg[cnt].m_size = ftell(tmpf) - msg[cnt].m_offset;
  951.     else
  952.         msg[cnt].m_size = ftell(fp) - msg[cnt].m_offset;
  953.     msg[cnt].m_lines = lines;
  954.     /* remember where we were to seek to for when we append new mail */ 
  955.     if (append)
  956.         cnt++;
  957.     }
  958.     if (append == 1) /* merge_folders takes care of this for append == 2 */
  959.     msg[cnt].m_offset = ftell(fp);
  960.     close_lock(file, fp);
  961.     if (isoff(glob_flags, READ_ONLY)) {
  962.     if (had_error && msg_found && append == 1 && cnt == MAXMSGS-append) {
  963.         wprint("Using read-only mode.\n");
  964.         turnon(glob_flags, READ_ONLY);
  965.         had_error = 0;    /* return successfully anyway */
  966.     }
  967.     (void) fclose(tmpf);
  968.     if (!(tmpf = fopen(tempfile, "r"))) {
  969.         error("Unable to open %s for reading", tempfile);
  970.         return -1;
  971.     }
  972.     }
  973.     return !had_error;
  974. }
  975.